﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HttpTest
{
    class HttpWarpper
    {
        public delegate string RequestDelegate(string endpoint, string requestBody, HttpClient.RequestMethod requestMethod);
        public event RequestDelegate onRequest;


        public unsafe delegate void* MsgDelegate(void* path, void* method, void* body);

        [DllImport("httplibdll.dll", EntryPoint = "set_callback", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        static extern void set_callback(MsgDelegate updateDelegate);


        [DllImport("httplibdll.dll", EntryPoint = "http_startup", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        [return: MarshalAs(UnmanagedType.I1)]
        unsafe static extern bool http_startup(void* ip, int port);

        [DllImport("httplibdll.dll", EntryPoint = "http_stop", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        static extern void http_stop();


        [DllImport("httplibdll.dll", EntryPoint = "http_post_upload", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        unsafe static extern void* http_post_upload(void* ip, int port, void* endpoint, void* name, void* content, int content_len, void* filename, void* contentType);

        public unsafe static string Post_Upload(string ip, int port, string endpoint, string file_key, IntPtr content, int content_len, string filename, string contentType)
        {
            void* _ip = Marshal.StringToHGlobalAnsi(ip).ToPointer();
            void* _endpoint = Marshal.StringToHGlobalAnsi(endpoint).ToPointer();
            void* _name = Marshal.StringToHGlobalAnsi(file_key).ToPointer();
            void* _content = content.ToPointer();
            void* _filename = Marshal.StringToHGlobalAnsi(filename).ToPointer();
            void* _contentType = Marshal.StringToHGlobalAnsi(contentType).ToPointer();
            return Marshal.PtrToStringAnsi(new IntPtr(http_post_upload(_ip, port, _endpoint, _name, _content, content_len, _filename, _contentType)));
        }

        unsafe void* _onRequest(void* path, void* method, void* body)
        {
            string content = onRequest?.Invoke(Marshal.PtrToStringAnsi(new IntPtr(path)), Marshal.PtrToStringAnsi(new IntPtr(body)), HttpClient.RequestMethod.POST);
            if (content != null)
            {
                return Marshal.StringToHGlobalAnsi(content).ToPointer();
            }
            else
            {
                return IntPtr.Zero.ToPointer();
            }
        }

        string ip;
        int port;

        public unsafe HttpWarpper(string _ip, int _port)
        {
            msgDelegate = new MsgDelegate(_onRequest);
            set_callback(msgDelegate);
            ip = _ip;
            port = _port;
        }

        ~HttpWarpper()
        {
            Stop();
        }

        public unsafe bool Start()
        {
            void* ip_ptr = Marshal.StringToHGlobalAnsi(ip).ToPointer();
            return http_startup(ip_ptr, port);
        }

        public void Stop()
        {
            http_stop();
        }

        MsgDelegate msgDelegate;

    }

    public unsafe class FFmpegDemuxerWrapper
    {
        [DllImport("httplibdll.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        unsafe static extern void* getDemuxerInstance(void*mrl);

        [DllImport("httplibdll.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        unsafe static extern void releaseDemuxerInstance(void*instance);

        [DllImport("httplibdll.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        [return: MarshalAs(UnmanagedType.I1)]
        unsafe static extern bool Demux(void* instance, void** ppVideo, int* pnVideoBytes, long* pts = null);

        public delegate void BufferGrab(void*buf,int len);
        public event BufferGrab onBufferGrab;

        void grab()
        {
            void* ppVideo;
            int pnVideoBytes;
            while (b_run)
            {
                if (Demux(instance, &ppVideo, &pnVideoBytes))
                {
                    onBufferGrab?.Invoke(ppVideo, pnVideoBytes);
                }
                
            }
        }
        Thread th;
        bool b_run=true;
        void* instance = null;
        public FFmpegDemuxerWrapper(string mrl)
        {
            instance = getDemuxerInstance(Marshal.StringToHGlobalAnsi(mrl).ToPointer());
            th = new Thread(grab);
            th.Start();
        }

        ~FFmpegDemuxerWrapper()
        {
            b_run = false;
            th.Abort();
            releaseDemuxerInstance(instance);
        }

    }
}
